
#include "si7021_config.h"

#define HIGH_LOW_TO_INT(high, low) (        \
    ((uint16_t) (((uint16_t) (high)) << 8)) \
    + ((uint16_t) ((low) & 0xFF))           \
    )

#define SI_7021_ADDR 				0x40

#define DEFAULT_USER_SETTING 		0x3A

#define ADC_BIT_SETTING_12  0
#define ADC_BIT_SETTING_11  3
#define ADC_BIT_SETTING_10  2
#define ADC_BIT_SETTING_8   1

#define SI_7021_INIT_DELAY_MS         50

#define ADC_12_BIT_CONV_TIME_MS       20
#define ADC_11_BIT_CONV_TIME_MS       15
#define ADC_10_BIT_CONV_TIME_MS       10
#define ADC_8_BIT_CONV_TIME_MS         5

#define SI_7021_USER_REG_WRITE               0xE6
#define SI_7021_USER_REG_READ                0xE7
#define SI_7021_MEASURE_RELATIVEHUMIDITY     0xF5
#define SI_7021_MEASURE_TEMPERATURE          0xF3
#define SI_7021_READ_TEMPERATURE             0xE0

#define SI_7021_RESET                        0xFE

static uint8_t humidityAccuracySet(uint8_t measureAccuracy) {
	uint8_t errorCode, currentValue;

	currentValue = DEFAULT_USER_SETTING;
    errorCode = si7021_hal_i2c_read_device_reg(SI_7021_ADDR, SI_7021_USER_REG_READ, &currentValue, 1);
	if (errorCode != 1) {
		return 0;
	}

	// ADCbits[0]: USER REGISTER bit 0
	// ADCbits[1]: USER REGISTER bit 7
	// USER REGISTER (7 bit): X X X X X X X
	//                        |           |
	//                     ADCBit[1]   ADCBit[0]
	currentValue = (currentValue & (0x7E)) | (((measureAccuracy & 0x2) << 6) | ((measureAccuracy & 0x1)));
    errorCode = si7021_hal_i2c_write_device_reg(SI_7021_ADDR, SI_7021_USER_REG_WRITE, &currentValue, 1);
	return errorCode;
}

uint8_t si7021_init(uint8_t accuracy)
{
	uint8_t ret = 1;
	uint8_t registerSetting;
	uint8_t resetMsg = SI_7021_RESET;

	// Send the reset command to the temperature sensor
	if (si7021_hal_i2c_write_device(SI_7021_ADDR, &resetMsg, 1) != 1) {
		ret = 0;
	}

	switch (accuracy) {
	case 12:
//		measurementReadyDelayMs = ADC_12_BIT_CONV_TIME_MS;
		registerSetting = ADC_BIT_SETTING_12;
		break;
	case 11:
//		measurementReadyDelayMs = ADC_11_BIT_CONV_TIME_MS;
		registerSetting = ADC_BIT_SETTING_11;
		break;
	case 10:
//		measurementReadyDelayMs = ADC_10_BIT_CONV_TIME_MS;
		registerSetting = ADC_BIT_SETTING_10;
		break;
	case 8:
//		measurementReadyDelayMs = ADC_8_BIT_CONV_TIME_MS;
		registerSetting = ADC_BIT_SETTING_8;
		break;
	default:
		ret = 0;
		break;
	}
	si7021_hal_delay_ms(10); //delay 10ms after reset
	ret = humidityAccuracySet(registerSetting);

	return ret;
}

uint8_t si7021_start_measure(void)
{
    uint8_t errorCode, command;

    command = SI_7021_MEASURE_RELATIVEHUMIDITY;
    errorCode = si7021_hal_i2c_write_device(SI_7021_ADDR, &command, 1);
    return errorCode;
}

uint8_t si7021_read_temp_val(uint32_t* temperature)    		//temperatureMilliC
{
    uint8_t errorCode;
//    uint8_t command;
    int32_t temperatureCalculation;
    uint8_t buffer[2];

//    command = SI_7021_READ_TEMPERATURE;
    errorCode = si7021_hal_i2c_read_device_reg(SI_7021_ADDR, SI_7021_READ_TEMPERATURE, buffer, 2);
    if (errorCode == 1) {
        //temperature (milliC) = 1000 * (175.72 * ADC /65536 - 46.85)
        //                     = (1000 * ( 5624 * ADC / 8192 - 11994 )) / 256
        temperatureCalculation = HIGH_LOW_TO_INT(buffer[0], buffer[1]);
        temperatureCalculation = 5624 * temperatureCalculation;
        temperatureCalculation = temperatureCalculation >> 13;
        temperatureCalculation = temperatureCalculation - 11994;
        temperatureCalculation = (temperatureCalculation * 1000) >> 8;
        *temperature = temperatureCalculation;
		return 1;
    }
    else{
        return 0;
    }
}

uint8_t si7021_read_humi_val(uint16_t* relativeHumidity)		//100%*100
{
    uint8_t errorCode;
    uint32_t relativeHumidityCalculation;
    uint8_t buffer[3];

    errorCode = si7021_hal_i2c_read_device(SI_7021_ADDR, buffer, 3);
    if(errorCode == 1){
        //Relative Humidity in % is calculated as the following:
        //let D = data from Si7021;
        //%RH = ((125 * D) / 65536) - 6;
        //
        //to calculate the Relative Humidity in Centi Percentage:
        //Centi%RH = (((125 * D) / 65536) - 6) * 100
        //         = (((100 * 125 * D) / 65536) - 600);
        relativeHumidityCalculation = HIGH_LOW_TO_INT(buffer[0], buffer[1]);
        relativeHumidityCalculation = relativeHumidityCalculation * 100;
        relativeHumidityCalculation = relativeHumidityCalculation * 125;
        relativeHumidityCalculation = relativeHumidityCalculation >> 16;
        relativeHumidityCalculation = relativeHumidityCalculation - 600;
        *relativeHumidity = (uint16_t)relativeHumidityCalculation;
		return 1;
    }
    else{
        return 0;
    }
}

